#チャンクの設定
knitr::opts_chunk$set(
  warning = FALSE,       
  message = FALSE,   
  cache = TRUE,
  comment = "",
  fig.align = "center"  
)

set.seed(27)             
#チャンクの設定について
#cache = TRUE:処理結果を保存しておく→TRUEでKnitするときに計算時間節約
#eval=FALSE:コードのみを出力し、計算を行わない場合
#echo=FALSE:コードを見せず、結果のみ出力する場合
getwd()

1. はじめに

 本研究では、防衛庁・防衛省が発行してきた「防衛白書」を使用して、探索的なテキスト分析を行う。目的は、防衛白書の記述内容を計量テキスト分析によって可視化し、日本の防衛政策の変遷を客観的に分析することである。1976年~2021年に発行された防衛白書の全テキストを分析対象として、政策決定者たちが他国をどのように分析してきたかを明らかにすることを試みた。

2. 使用するデータについて

 本研究の分析対象は、防衛省(2007年1月9日に省へ昇格するまでは防衛庁)が発行している「防衛白書」である。「防衛白書」は1970年に第1回が発行され、第2回の1976年からは毎年発行されている。連続にならず分析上不具合が生じるため、1970年は対象外として、1976年から2021年までの46年分を使用する。以降、各年の防衛白書の呼称を「防衛白書2021」のように記す。
 使用する防衛白書は全て防衛省のWEBサイトで公開されており1、誰でも閲覧可能となっている。そこで、文章の収集を、カット&ペースト(防衛白書1976、1998~2001、2003~2004、2020~2021)とRによるスクレイピング(防衛白書1977~1997、2002、2005~2019)で行った。発行年によって体裁および文章量が大幅に異なっていたため、その年ごとに容易な方法で収集した。白書の本編、コラム等、文章として収集可能な全範囲を分析対象とし、資料編、画像、図表は対象から除いた。ただし、Rによるスクレイピングで、画像の説明等、取り除くことが技術上困難な文章については、前処理の段階で消すことができるため、そのままテキストデータに残している。その年の文章量によって異なるが、1年分の白書の全記述をテキストデータにするためにおよそ1時間~2時間かかった。スクレイピングを実行したRスクリプトと、作成した全テキストデータは別途公開する。

3.テキスト分析の手法

 本研究の分析では、フリーのデータ解析ソフトウェアであるRを用いる。具体的な作業としては、①収集したテキストの前処理、②文書行列の作成、③統計分析の適用(KeyATM、頻度集計、ワードクラウド、共起ネットワーク)を行った。
 まず、英語のようにスペースで単語分けをされていない日本語のテキストを分析する場合、分かち書きをする必要がある。そこで収集した白書データを、Rパッケージの「Quanteda」を使用して、「コーパス」と呼ばれる文書の集合を作る。次に、コンピューターで処理できるように、「トークン化」によって分かち書きをする。この段階で、記号や助詞、助動詞、年代を表す語(「同年」「現在」「平成」等)、さらに防衛白書を分析する上で不要な語(「参照」「図表」「項目」等)を削除し、本来1単語であるはずが分割されてしまっている単語を結合する。
 なお、これまで日本語の前処理には、形態素解析ツール(「RMeCab」など)が用いられることが多かったが、「Quanteda」であれば、外部ツールを用いずに日本語のトークン化を行うことができ、処理結果も形態素解析の場合と大差がないため、本研究では「Quanteda」を使用している。
 次に、トークン化によって作成したトークンを文書ごとに集計した「文書行列」を作成する。文書行列では、行が文書、列が語と対応しており、セルの値がそれぞれの語が文書に登場する頻度を表す。
 以上のようにして作成した「文書行列」を用いると、統計的な分析を行うことができる。本研究では、防衛白書の記述の変遷を計量的に分析することを目的とするため、「KeyATM」「頻出語」「ワードクラウド」「共起ネットワーク」分析を行った。

#パッケージの読み込み
library("tidyverse")
library("readtext")
library("quanteda")
library("stm")
library("keyATM")
library("quanteda.textstats")
library("quanteda.textplots")
library("seededlda")
#ワーキングディレクトリの設定
setwd("/mnt/c/users/shimi/sotsuron")

4. テキストの前処理

4-1. テキストデータの読み込み

modtext<-readtext(file="./hakusho/*.txt",
                  encoding = "utf-8") %>% 
  mutate(year = str_extract(doc_id, "\\d\\d\\d\\d") %>% 
           as.numeric())
mod1976<-readtext(file="hakusho/w1976.txt",
                  encoding = "utf-8")

4-2. コーパスの作成

corp <- corpus(modtext, docid_field = "doc_id")
#corpusは、data.frameもしくは、文字列ベクトルから作成され、文書および文書変数を元の状態で格納する。
corp1976 <- corpus(mod1976, docid_field = "doc_id")
summary(corp)

4-3.トークン化

toks<-tokens(corp, remove_numbers = TRUE,  remove_punct = TRUE, 
             remove_symbols = TRUE) %>% 
  tokens_remove(c(stopwords("ja", source = "marimo"),
                 "章","第","の","部","と","て","は","に","を","における",
                  "が","し","ば","で","など", "こと","って","なる","において",
                  "できる","進む","ページ","れる","とともに","向け","とる","あっ",
                  "てい","られる","もの","させる","かつ","させる","及び","行う",
                  "I","II","III","受け","んで","戻る","のみ","なら","項目","白書",
                  "三つ","参照","含む","に際して","ます","にし","とも","実施","取り組み",
                  "同年","指摘","わが国","図表","利用","活用","はじめ","両国","重要","使用",
                  "関係","可能","つつ","政府","推進","計画","現在","きた","以上",
                  "昭和","場合","という","各種","とおり","われ","今後","開催",
                  "必要","結果","場合","新た","引き続き","行い","提供","なお",
                  "といった","われる","および","資料","近年","行い","強化","見直し","なく",
                  "又は","目的","以降","同年","各種","見直し","図る","具体","努めて",
                 "平成","令和","昭和","活動"
  )) %>% 
  tokens_select(min_nchar=2)
#tokensは、corpusから作成され、分を語に分割した状態で格納する。tokensは語の位置関係を保持するため、複合語の選択・削除・結合を行える
#ひらがな等いらない語を消す
#トークン化
toks1976<-tokens(corp1976, remove_numbers = TRUE,  remove_punct = TRUE, 
             remove_symbols = TRUE) %>% 
  tokens_remove(c(stopwords("ja", source = "marimo"),
                 "章","第","の","部","と","て","は","に","を","における",
                  "が","し","ば","で","など", "こと","って","なる","において",
                  "できる","進む","ページ","れる","とともに","向け","とる","あっ",
                  "てい","られる","もの","させる","かつ","させる","及び","行う",
                  "I","II","III","受け","んで","戻る","のみ","なら","項目","白書",
                  "三つ","参照","含む","に際して","ます","にし","とも","実施","取り組み",
                  "同年","指摘","わが国","図表","利用","活用","はじめ","両国","重要","使用",
                  "関係","可能","つつ","政府","推進","計画","現在","きた","以上",
                  "昭和","場合","という","各種","とおり","われ","今後","開催",
                  "必要","結果","場合","新た","引き続き","行い","提供","なお",
                  "といった","われる","および","資料","近年","行い","強化","見直し","なく",
                  "又は","目的","以降","同年","各種","見直し","図る","具体","努めて",
                 "平成","令和","昭和","活動","the","たとえば"
  )) %>% 
  tokens_select(min_nchar=2)
#250回以上出てくる単語をつなげる
col <- toks %>% 
  textstat_collocations(min_count =250)
#10回以上出てくる単語をつなげる
col1976 <- toks1976 %>% 
  textstat_collocations(min_count =10)
col$collocation
col1976$collocation
col$z
col1976$z
toks_comp <- tokens_compound(toks, col[col$z > 26], concatenator = "") %>% 
  tokens_keep(min_nchar = 2)
toks_comp1976 <- tokens_compound(toks1976, col1976[col1976$z > 26], concatenator = "") %>% 
  tokens_keep(min_nchar = 2)
#つながり方がおかしい単語をつなげる
toks_comp<- tokens_compound(toks_comp, pattern = c("フリゲート","人民解放軍",
                                                   "日米同盟","ミサイル防衛","海上輸送",
                                                   "共同演習","ハイレベル交流","ASEAN諸国",
                                                   "安全保障","海上自衛隊","災害派遣",
                                                   "西側諸国","陸上自衛隊","国際情勢",
                                                   "共同訓練","航空自衛隊","軍事情勢",
                                                   "輸送能力","安全保障"))
toks_comp1976<- tokens_compound(toks_comp1976, pattern = c("海上自衛隊","災害派遣","西側諸国",
                                                   "陸上自衛隊","国際情勢","共同訓練",
                                                   "航空自衛隊","軍事情勢","輸送能力",
                                                   "レーダーサイト",
                                                   "安全保障"))

4-4. 文章行列の作成

dfm <- dfm(toks_comp) 
dfm <- dfm %>% 
  dfm_trim(min_termfreq = 1500)%>% 
  dfm_remove(pattern = c("防衛", "自衛隊"))
dfm1976 <- dfm(toks_comp1976) 

5. 分析結果

5-1. KeyATM

 KeyATM(Keyword Assisted Topic Models)2とは、「準教師あり学習モデル」であり、人間によって与えられた語彙を手がかりとして、機械がコーパスから語の関係を学習して文書の分類を行う統計モデルである。このモデルは、教師ありモデルと教師なしモデルの弱点を補うために使われ出した手法であり、どの語を選択するかが決定的に重要になる。 3
 本研究では、直近数年間の防衛白書で注目されている国々が、これまでどの程度関心が寄せられてきたのか時系列を追って明らかにしたい。そこで、直近5か年(2017年~2021年)の防衛白書のダイジェスト・第Ⅰ部「わが国を取り巻く安全保障環境」で項目を立てて言及のある国を分析の対象とする。ダイジェストはその年に最も伝えたい内容を記しているはずであり、そこで言及のある国は日本の安全保障上、重視していると考えられるためだ。表1は、防衛白書2017から2021で言及のある国を登場順にまとめたものである。なお、「中東・北アフリカ」「欧州」のような地域名で項目を立てている部分は、1国について詳細に言及している部分よりも重要度が低いので分析対象外とする。また、「ロシア」は、冷戦終結まで「ソ連(ソビエト連邦)」と記されていた。これらの点を踏まえ、設定するキーワードを「米国」「北朝鮮」「中国」「ロシア」「ソ連」とした。
 時間軸を考慮せずに、防衛白書1976~2021の全テキストデータにおける各国のトピック割合を分析した結果が図1、各国のトピック割合の変遷を示したのが図2、図2で1か国ずつ変遷を表した図を1つにまとめたものが図3である。図4は、図3から米国を除き、非民主主義国のみでトピック割合の変遷を示したものである。

表1.防衛白書2017~2021概観で言及のある国々
Year 1 2 3 4
2017 米国 北朝鮮 中国 ロシア
2018 米国 北朝鮮 中国 ロシア
2019 米国 中国 北朝鮮 ロシア
2020 米国 中国 北朝鮮 ロシア
2021 米国 中国 北朝鮮 ロシア
keyatm_docs <- keyATM_read(texts = dfm)
summary(keyatm_docs)
#キーワードのリストを作成
keywords <- list(
  米国    = c("米国"),
  北朝鮮  =c("北朝鮮"),
  中国 = c("中国"),
  ロシア = c("ロシア"),
  ソ連 = c("ソ連"))
#白書全体に占めるそれぞれのトピックの割合
visualize_keywords(docs = keyatm_docs,
                   keywords = keywords)
図1.防衛白書全体に占める各国のトピック割合
#時系列を入れる
time <- modtext %>%
  mutate(year = str_extract(doc_id, "\\d\\d\\d\\d") %>%
           as.numeric()) %>%
  filter(year >= 1976) %>%
  mutate(time = year - 1975) %>% 
  select(doc_id, time)
time
time$time
out <- keyATM(docs              = keyatm_docs,                         
              no_keyword_topics = 10,  #自分が指定したトピックの他に何トピック抜き出すか                                 
              keywords          = keywords,                      
              model             = "dynamic",                           
              model_settings    = list(time_index =time$time,
                                       num_states = length(time$time)),                
              options           = list(seed = 250,
                                       parallel_init = TRUE,
                                       store_theta = TRUE))
top_words(out, 30)
plot_timetrend(out, time = time$time + 1975)
図2.各国のトピック割合の変遷
theta_ls <- out$values_iter$theta_iter
#図2を1つの図にまとめて表現するためのコード
theta_1 <- theta_2 <- theta_3 <- theta_4 <- theta_5 <- matrix(NA, length(time$time), length(theta_ls))
for (iter in 1:length(theta_ls)) {
  theta_temp <- theta_ls[[iter]]
  theta_1[, iter] <- theta_temp[, 1]
  theta_2[, iter] <- theta_temp[, 2]
  theta_3[, iter] <- theta_temp[, 3]
  theta_4[, iter] <- theta_temp[, 4]
  theta_5[, iter] <- theta_temp[, 5]
}
lwr_fn <- function(x) quantile(x, probs = 0.025)
upr_fn <- function(x) quantile(x, probs = 0.975)
us <- tibble(lwr = apply(theta_1, 1, lwr_fn),
                upr = apply(theta_1, 1, upr_fn),
                mean = apply(theta_1, 1, mean),
                type = "米国",
                year = 1976:2021)

nkorea <- tibble(lwr = apply(theta_2, 1, lwr_fn),
             upr = apply(theta_2, 1, upr_fn),
             mean = apply(theta_2, 1, mean),
             type = "北朝鮮",
             year = 1976:2021)

china <- tibble(lwr = apply(theta_3, 1, lwr_fn),
                 upr = apply(theta_3, 1, upr_fn),
                 mean = apply(theta_3, 1, mean),
                 type = "中国",
                 year = 1976:2021)

russia <- tibble(lwr = apply(theta_4, 1, lwr_fn),
               upr = apply(theta_4, 1, upr_fn),
               mean = apply(theta_4, 1, mean),
               type = "ロシア",
               year = 1976:2021)

USSR <- tibble(lwr = apply(theta_5, 1, lwr_fn),
                 upr = apply(theta_5, 1, upr_fn),
                 mean = apply(theta_5, 1, mean),
                 type = "ソ連",
                 year = 1976:2021)
#米国、中国、北朝鮮、ソ連、ロシア

bind_rows(USSR,russia,china,nkorea,us) %>% 
  ggplot(aes(x = year, y = mean, color = type)) +
  geom_line() +
  geom_point(aes(shape = type)) +
  theme_bw() +
  xlab("Year") + ylab("Estimated theta") +
  scale_color_hue() +
  theme(legend.title = element_blank())
図3.トピック割合の変遷
図4.非民主主義国のトピック割合の変遷

5-2. 頻度集計・ワードクラウド

 防衛白書2021の構成は、「第Ⅰ部:わが国を取り巻く安全保障環境」「第Ⅱ部:わが国の安全保障環境・防衛政策」「第Ⅲ部:わが国防衛の三つの柱」「第Ⅳ部:防衛力を構成する中心的な政策など」となっている。細かな構成は毎年変化があるものの、軍事情勢や日本の防衛政策については必ず何らかの記述がある。そのため、頻度集計を行い時系列で比較することで、何を強調していたか、その変化を観察することができる。そこで、防衛白書1976から5年ごとの白書を用いて、頻度集計を行った。名詞のみを指定して、頻出上位20語を棒グラフで可視化した結果は5-2-1の通りである。また、頻度集計表を頻度の高い単語ほど、大きいフォントで描かれるワードクラウドでも可視化した。分析結果は5-2-2の通りである。

#保存用のコード
#  png("wc1976.png", height = 700, width = 700, res = 250)

5-2-1. 頻度集計

防衛白書1976

dfm1976<-dfm(toks_comp1976,remove="") %>% 
  dfm_remove("^[ぁ-ん]+$", valuetype = "regex", min_nchar = 2)
topwords_title1976 <- topfeatures(dfm1976, 30)
fcm1976 <- dfm1976 %>%
  fcm()
fcm_1976_2 <- fcm1976 %>% 
  fcm_select(pattern = names(topwords_title1976)) %>% 
  fcm_remove(pattern = c("平成", "令和"))
size <- rowSums(fcm_1976_2) %>% sqrt
# ワードリストを作成

sorted.freq.list1976 <- sort(topwords_title1976, decreasing = TRUE)

barplot(sorted.freq.list1976[1 : 20], 
        las = 2, 
        cex.names = 1.0,
        xlab = "単語",
        ylab = "頻度")
防衛白書1976頻出20語

防衛白書1981

防衛白書1981頻出上位20語

防衛白書1986

防衛白書1986頻出上位20語

防衛白書1991

防衛白書1991頻出上位20語

防衛白書1996

防衛白書1996頻出上位20語

防衛白書2001

防衛白書2001頻出上位20語

防衛白書2006

防衛白書2006頻出上位20語

防衛白書2011

防衛白書2011頻出上位20語

防衛白書2016

防衛白書2016頻出上位20語

防衛白書2021

防衛白書2021頻出上位20語

5-2-2. ワードクラウド

#保存用のコード
# png("top1976.png", height = 900, width = 1600, res = 250)
# devoff()

防衛白書1976

防衛白書1976ワードクラウド

防衛白書1981

防衛白書1981ワードクラウド

防衛白書1986

防衛白書1986ワードクラウド

防衛白書1991

防衛白書1991ワードクラウド

防衛白書1996

防衛白書1996ワードクラウド

防衛白書2001

防衛白書2001ワードクラウド

防衛白書2006

防衛白書2006ワードクラウド

防衛白書2011

防衛白書2011ワードクラウド

防衛白書2016

防衛白書2016ワードクラウド

防衛白書2021

防衛白書2021ワードクラウド

5-3.共起ネットワーク

 第5章2節で単語の集計を行い、白書のテキスト内容を明らかにしてきたが、それらの単語がどのような文脈で使われているのかを明らかにするため、共起語分析を行った。共起語とは、分析対象とする単語の近くによく一緒に使われている単語のことで、どのように描写されているのか、どのような評価を受けているのかを明らかにできる。防衛白書で分析することで、頻出の語がどのような文脈で使用されているかを明らかにすることができると考える。分析では、防衛白書1976から5年おきの白書を用いて、それぞれ特徴的な上位30語を選択、共起回数の閾値を0.85に設定した。分析結果は以下の通りである。黒丸の大きさは語の頻度を、線の太さは共起語の関係の強さを、それぞれ示している。

# 保存用のコード
#   png("kk1976.png", height = 900, width = 1600, res = 250)

防衛白書1976

dfm1976<-dfm(toks_comp1976,remove="") %>% 
  dfm_remove("^[ぁ-ん]+$", valuetype = "regex", min_nchar = 2)
topwords_title1976 <- topfeatures(dfm1976, 30)
fcm1976 <- dfm1976 %>%
  fcm()
fcm_1976_2 <- fcm1976 %>% 
  fcm_select(pattern = names(topwords_title1976)) %>% 
  fcm_remove(pattern = c("平成", "令和"))
size <- rowSums(fcm_1976_2) %>% sqrt
fcm_1976_2 %>% 
  textplot_network(
                   min_freq = 0.85,
                   vertex_size = size / max(size)*3,
                   edge_alpha = 0.7,
                   edge_size = 0.7,
                   vertex_labelsize = 5)
防衛白書1976共起ネットワーク

防衛白書1981

防衛白書1981共起ネットワーク

防衛白書1986

防衛白書1986共起ネットワーク

防衛白書1991

防衛白書1991共起ネットワーク

防衛白書1996

防衛白書1996共起ネットワーク

防衛白書2001

防衛白書2001共起ネットワーク

防衛白書2006

防衛白書2006共起ネットワーク

防衛白書2011

防衛白書2011共起ネットワーク

防衛白書2016

防衛白書2016共起ネットワーク

防衛白書2021

防衛白書2021共起ネットワーク

  1. 防衛省ホームページ「防衛白書の検索」http://www.clearing.mod.go.jp/hakusho_web/?_ga=2.189913708.659932794.1647144920-1909311622.1558770267↩︎

  2. keyATM https://keyatm.github.io/keyATM/index.html (2022年1月29日閲覧)↩︎

  3. カタリナック,エイミー・渡辺耕平(2019)「日本語の量的テキスト分析」『早稲田大学高等研究所紀要』11巻、pp133-143↩︎